#import "RNNewItemSheetController.h"
#import "RNConstants.h"
#import "RNAisle.h"
#import "RNStore.h"
#import "RNCategory.h"
#import "RNItem.h"
#import "RNList.h"
#import "RNListItem.h"
#import "NSManagedObjectContext+SRAdditions.h"
#import "NSBrowser+SRAdditions.h"
#import "RNCategoryBrowserCell.h"
#import "MainWindowController.h"
#import "NSString+SRAdditions.h"

@interface RNNewItemSheetController (RNNewItemSheetControllerPrivateMethods)
-(void)loadCategories_:(NSSet *)categories intoAisle:(RNAisle *)aisle;
-(NSToolbarItem *)toolbarItemWithTag_:(NSInteger)tag;
-(void)addDescendentsOfObject_:(id)object toSet:(NSMutableSet *)categoriesToAdd;
@end

@implementation RNNewItemSheetController

// Top-level elements
@synthesize tabView = tabView_;
@synthesize toolbar = toolbar_;
@synthesize saveButton = saveButton_;
@synthesize categoriesController = categoriesController_;

// Category view
@synthesize categoryView = categoryView_;
@synthesize categoryViewNameField = categoryViewNameField_;
@synthesize categoryViewBrowser = categoryViewBrowser_;

// Item view
@synthesize itemView = itemView_;
@synthesize itemViewNameField = itemViewNameField_;
@synthesize itemViewBrowser = itemViewBrowser_;

// Store view
@synthesize storeView = storeView_;
@synthesize createAislesCheckBox = createAislesCheckBox_;
@synthesize storeViewNameField = storeViewNameField_;
@synthesize templateMatrix = templateMatrix_;

// Aisle view
@synthesize aisleView = aisleView_;
@synthesize aisleViewNameField = aisleViewNameField_;
@synthesize aisleViewStorePopUp = aisleViewStorePopUp_;
@synthesize aisleViewBrowser = aisleViewBrowser_;
@synthesize storesController = storesController_;

// List view
@synthesize listView = listView_;
@synthesize listViewNameField = listViewNameField_;

// Other properties
@synthesize categoriesControllerSortDescriptors = categoriesControllerSortDescriptors_;
@synthesize storePopUpSortDescriptors = storePopUpSortDescriptors_;
@synthesize tabViewSizes = tabViewSizes_;
@synthesize categoriesForNewAisle = categoriesForNewAisle_;
@synthesize listToAddNewItem = listToAddNewItem_;

-(void)awakeFromNib {
    NSSortDescriptor *leafDescriptor = [[NSSortDescriptor alloc] initWithKey:@"isLeaf" ascending:YES];
    NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
    [self setCategoriesControllerSortDescriptors:[NSArray arrayWithObjects:leafDescriptor, titleDescriptor, nil]];
    [self setStorePopUpSortDescriptors:[NSArray arrayWithObject:titleDescriptor]];
    [self setCategoriesForNewAisle:[NSMutableSet set]];
    [[self aisleViewBrowser] setCellPrototype:[[RNCategoryBrowserCell alloc] initTextCell:@""]];

    [[self categoryViewBrowser] setAutohidesScroller:YES];
    [[self aisleViewBrowser] setAutohidesScroller:YES];
    [[self aisleViewBrowser] setTarget:self];
    [[self aisleViewBrowser] setDoubleAction:@selector(aisleBrowserDoubleAction:)];
    [[self itemViewBrowser] setAutohidesScroller:YES];
    
    NSArray *items = [[self toolbar] items];
    NSArray *views = [NSArray arrayWithObjects:[self itemView], [self listView], [self storeView], [self aisleView], [self categoryView], nil];
    [self setTabViewSizes:[[NSMutableArray alloc] initWithCapacity:[views count]]];
    for (NSToolbarItem *item in items) {
        if ([[item itemIdentifier] isEqualToString:NSToolbarFlexibleSpaceItemIdentifier] || [[item itemIdentifier] isEqualToString:NSToolbarSeparatorItemIdentifier])
            continue;
        
        NSTabViewItem *tabViewItem = [[NSTabViewItem alloc] initWithIdentifier:nil];
        [[self tabViewSizes] addObject:[NSValue valueWithSize:[[views objectAtIndex:[item tag]] bounds].size]];
        [tabViewItem setView:[views objectAtIndex:[item tag]]];
        [[self tabView] addTabViewItem:tabViewItem];
    }
    
    [[self saveButton] setTarget:self];
    [self selectItemWithTag:RNNewItemSheetItemToolbarItem];
}

-(void)displayNewItemSheet {
    [NSApp beginSheet:[self window] modalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:nil];
    if ([[self toolbar] selectedItemIdentifier] == nil)
        [self selectItemWithTag:RNNewItemSheetItemToolbarItem];
}

-(void)createItemWithString:(NSString *)itemString addToList:(RNList *)list {
    [self loadWindow];
    [self setListToAddNewItem:list];
    [self selectItemWithTag:RNNewItemSheetItemToolbarItem];
    [[self itemViewNameField] setStringValue:itemString];
    [self displayNewItemSheet];
}

-(IBAction)cancelNewItemSheet:(id)sender {
    [NSApp endSheet:[self window] returnCode:0];
}

-(void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
    [sheet orderOut:self];
}


#pragma mark -
#pragma mark Toolbar methods

-(void)selectItemWithTag:(NSInteger)tag {
    if (![self isWindowLoaded])
        [self loadWindow];
    NSToolbarItem *selectedItem = [self toolbarItemWithTag_:tag];
    
    // Set 'Save' button's action to reflect new view
    NSString *actionString = [NSString stringWithFormat:@"save%@:", [selectedItem label]];
    [[self saveButton] setAction:NSSelectorFromString(actionString)];
    
    // Select the given item in the toolbar
    [[self toolbar] setSelectedItemIdentifier:[selectedItem itemIdentifier]];

    // Update tab view
    [[self tabView] selectTabViewItemAtIndex:tag];

    // Resize sheet to fit new view
    NSSize viewSize = [[[self tabViewSizes] objectAtIndex:tag] sizeValue];
    viewSize = [[self window] frameRectForContentRect:NSMakeRect(0, 0, viewSize.width, viewSize.height)].size;
    viewSize.height += 34;
//    viewSize.height += [[self bottomBar] frame].size.height;
    NSRect windowFrame = [[self window] frame];
    CGFloat xPosition = windowFrame.origin.x + (windowFrame.size.width / 2) - (viewSize.width / 2);
    CGFloat yPosition = windowFrame.origin.y + windowFrame.size.height - viewSize.height;
    NSRect newWindowFrame = NSMakeRect(xPosition, yPosition, viewSize.width, viewSize.height);
    [[self window] setFrame:newWindowFrame display:YES animate:YES];
    [[self window] display]; // Without this, I was getting drawing artifacts from previously selected item
}

- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar {
    NSArray *items = [toolbar items];
    NSMutableArray *selectableItems = [NSMutableArray array];
    for (NSToolbarItem *item in items) {
        if ([item tag] >= 0)
            [selectableItems addObject:[item itemIdentifier]];
    }
    return selectableItems;
}

-(IBAction)toolbarItemClicked:(id)sender {
    [self selectItemWithTag:[(NSToolbarItem *)sender tag]];
}

-(NSToolbarItem *)toolbarItemWithTag_:(NSInteger)tag {
    for (NSToolbarItem *toolbarItem in [[self toolbar] items]) {
        if ([toolbarItem tag] == tag)
            return toolbarItem;
    }
    return nil;
}


#pragma mark -
#pragma mark Category methods

// TODO: WHAT WAS THIS SUPPOSED TO DO?
-(IBAction)doubleClickCategory:(NSArray *)categoryArray {
//    NSAssert([categoryArray count] != 0, @"double clicked and got empty array");
//    Category *firstObject = [categoryArray objectAtIndex:0];
//    if ([[firstObject subcategories] count] == 0) {
//        NSBeep();
//        return;
//    }
//    [self setPopupSelectedCategory:firstObject];
}

-(IBAction)saveCategory:(id)sender {
    NSString *categoryTitle = [[self categoryViewNameField] stringValue];
    NSArray *selectedObjects = [[self categoriesController] selectedObjects];
    [NSApp endSheet:[self window] returnCode:1];
    [[self categoryViewNameField] setStringValue:@""];
    [[self window] makeFirstResponder:[self categoryViewNameField]];
    
    NSArray *duplicates = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameCategory withPredicate:[NSPredicate predicateWithFormat:@"title LIKE %@", categoryTitle]];
    if ([categoryTitle length] == 0 || [duplicates count] > 0) 
        return;

    RNCategory *parentCategory = [selectedObjects count] == 0 ? nil : [selectedObjects objectAtIndex:0];
    RNCategory *newCategory = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameCategory inManagedObjectContext:[self managedObjectContext]];
    [newCategory setTitle:categoryTitle];
    [newCategory setParentCategory:parentCategory];
}


#pragma mark -
#pragma mark Item methods

-(IBAction)saveItem:(id)sender {
    NSString *itemTitle = [[self itemViewNameField] stringValue];
    NSArray *selectedObjects = [[self categoriesController] selectedObjects];
    [NSApp endSheet:[self window] returnCode:1];
    [[self itemViewNameField] setStringValue:@""];
    [[self window] makeFirstResponder:[self itemViewNameField]];
    
    NSArray *duplicates = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameItem withPredicate:[NSPredicate predicateWithFormat:@"title LIKE %@", itemTitle]];
    if ([itemTitle length] == 0 || [duplicates count] > 0)
        return;
    
    RNCategory *selectedCategory = [selectedObjects count] == 0 ? nil : [selectedObjects objectAtIndex:0];
    RNItem *newItem = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameItem inManagedObjectContext:[self managedObjectContext]];
    [newItem setTitle:itemTitle];
    [newItem setCategory:selectedCategory];
    
    // Add new item to all store aisles that track the item's category
    NSArray *aisles = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameAisle withPredicate:@"%@ IN categories", selectedCategory];
    [newItem addAisles:[NSSet setWithArray:aisles]];

    RNList *currentList = [self listToAddNewItem];
    if (!currentList)
        return;
    RNListItem *newListItem = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameListItem inManagedObjectContext:[self managedObjectContext]];
    [newListItem setItem:newItem];
    [newListItem setCategory:[newItem category]];
    [newListItem addAisles:[newItem aisles]];
    [newListItem setList:currentList];
    [self setListToAddNewItem:nil];
}


#pragma mark -
#pragma mark Store methods

-(IBAction)saveStore:(id)sender {
    NSString *storeTitle = [[self storeViewNameField] stringValue];
    NSCellStateValue createAislesState = [[self createAislesCheckBox] state];
    [NSApp endSheet:[self window] returnCode:1];
    [[self storeViewNameField] setStringValue:@""];

    NSArray *duplicates = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameStore withPredicate:[NSPredicate predicateWithFormat:@"title LIKE %@", storeTitle]];
    if ([storeTitle length] == 0 || [duplicates count] > 0)
        return;
    
    RNStore *newStore = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameStore inManagedObjectContext:[self managedObjectContext]];
    [newStore setValue:storeTitle forKey:RNTitleKey];

//    if ([[newStore title] containsString:@"albertson"])
//        [newStore setIcon:[NSImage imageNamed:@"store_albertsons.png"]];
//    else if ([[newStore title] matchesExpression:@"(?i)wal-?mart"])
//         [newStore setIcon:[NSImage imageNamed:@"sourceList_walmart.png"]];
//    else if ([[newStore title] containsString:@"farm fresh"])
//         [newStore setIcon:[NSImage imageNamed:@"sourceList_farmFresh.png"]];
//    else if ([[newStore title] containsString:@"food lion"])
//         [newStore setIcon:[NSImage imageNamed:@"sourceList_foodLion.png"]];
//    else 
         [newStore setIcon:[NSImage imageNamed:@"sourceList_genericStore.png"]];
    
    if (createAislesState == NSOffState)
        return;
    
    NSString *selectedTemplateTitle = [[[self templateMatrix] selectedCell] title];
    NSString *plistTitle = [NSString stringWithFormat:@"%@Template", [[selectedTemplateTitle componentsSeparatedByString:@" "] objectAtIndex:0]];
    NSString *plistPath = [[NSBundle mainBundle] pathForResource:plistTitle ofType:@"plist"];
    NSDictionary *template = [NSDictionary dictionaryWithContentsOfFile:plistPath];
    for (NSString *aisleName in template) {
        NSArray *categoryNames = [[template valueForKey:aisleName] valueForKey:@"categories"];
        NSArray *categories = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameCategory withPredicate:@"title IN %@", categoryNames];
        
        RNAisle *newAisle = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameAisle inManagedObjectContext:[self managedObjectContext]];
        [newAisle setValue:aisleName forKey:RNTitleKey];
        NSNumber *aisleNumber = [[template valueForKey:aisleName] valueForKey:@"aisleNumber"];
        [newAisle setAisleNumber:aisleNumber];
        [newAisle setValue:newStore forKey:@"store"];
        NSSet *categoriesSet = [NSSet setWithArray:categories];
        [newAisle addCategories:categoriesSet];
        [self loadCategories_:categoriesSet intoAisle:newAisle];        
    }
}

-(void)loadCategories_:(NSSet *)categories intoAisle:(RNAisle *)aisle {
    for (RNCategory *category in categories) {
        NSSet *items = [category items];
        [aisle addItems:items];
        NSSet *listItems = [category listItems];
        [aisle addListItems:listItems];
        [self loadCategories_:[category subcategories]  intoAisle:aisle];
    }
}


#pragma mark -
#pragma mark Aisle methods

-(IBAction)saveAisle:(id)sender {
    NSString *aisleTitle = [[self aisleViewNameField] stringValue];
    NSArray *selectedStores = [[self storesController] selectedObjects];
    if (!selectedStores || [selectedStores count] == 0)
        return;
    RNStore *store = [selectedStores objectAtIndex:0];
    [NSApp endSheet:[self window] returnCode:1];
    [[self aisleViewNameField] setStringValue:@""];

    NSArray *duplicates = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameAisle withPredicate:[NSPredicate predicateWithFormat:@"title LIKE %@ AND store == %@", aisleTitle, store]];
    if ([aisleTitle length] == 0 || [duplicates count] > 0)
        return;
    
    RNAisle *newAisle = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameAisle inManagedObjectContext:[self managedObjectContext]];
    NSInteger aisleCount = [[store aisles] count];
    [newAisle setAisleNumber:[NSNumber numberWithInteger:aisleCount]];
    [newAisle setTitle:aisleTitle];
    [newAisle setStore:store];
    [newAisle addCategories:[self categoriesForNewAisle]];
    [self loadCategories_:[self categoriesForNewAisle] intoAisle:newAisle];
    [self setCategoriesForNewAisle:[NSMutableSet set]];
}

-(IBAction)addSelectedSubcategories:(id)sender {
    NSSet *selectedObjects = [NSSet setWithArray:[[self aisleViewBrowser] selectedItems]];
    [self addDescendentsOfObject_:selectedObjects toSet:[self categoriesForNewAisle]];
    [[self aisleViewBrowser] setNeedsDisplay:YES];
}

-(IBAction)removeSelectedSubcategories:(id)sender {
    NSSet *selectedObjects = [NSSet setWithArray:[[self aisleViewBrowser] selectedItems]];
    NSMutableSet *categoriesToRemove = [NSMutableSet set];
    [self addDescendentsOfObject_:selectedObjects toSet:categoriesToRemove];
    [[self categoriesForNewAisle] minusSet:categoriesToRemove];
    [[self aisleViewBrowser] setNeedsDisplay:YES];
}

-(IBAction)aisleBrowserDoubleAction:(id)sender {
    NSSet *selectedCategories = [NSSet setWithArray:[[self aisleViewBrowser] selectedItems]];
    if ([selectedCategories isSubsetOfSet:[self categoriesForNewAisle]]) 
        [self removeSelectedSubcategories:nil];
    else
        [self addSelectedSubcategories:nil];
}

-(void)addDescendentsOfObject_:(id)object toSet:(NSMutableSet *)categoriesToAdd {
    NSSet *subcategories = nil;
    if ([object isKindOfClass:[NSSet class]]) 
        subcategories = (NSSet *)object;
    else // object is a category - get the subcategories
        subcategories = [object subcategories];
    
    for (RNCategory *subcategory in subcategories) {
        [categoriesToAdd addObject:subcategory];
        [self addDescendentsOfObject_:subcategory toSet:categoriesToAdd];
    }
}

- (void)browser:(NSBrowser *)browser willDisplayCell:(id)cell atRow:(NSInteger)row column:(NSInteger)column {
    RNCategory *category = [browser itemAtRow:row inColumn:column];
    [cell setDisplaysIcon:[[self categoriesForNewAisle] containsObject:category]];
}

- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
    if (item) 
        return [[item subcategories] count];
    
    NSArray *categories = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameCategory withPredicate:@"parentCategory == nil"];
    return [categories count];
}

-(id)browser:(NSBrowser *)browser child:(NSInteger)childIndex ofItem:(id)item {
    if (item)  
        return [[[item subcategories] sortedArrayUsingDescriptors:[self categoriesControllerSortDescriptors]] objectAtIndex:childIndex];
    NSArray *categories = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameCategory sortedWithDescriptors:[self categoriesControllerSortDescriptors] withPredicate:@"parentCategory == nil"];
    return [categories objectAtIndex:childIndex];
}

- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
    return [item isLeaf];
}

- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
    return [item title];
}


#pragma mark -
#pragma mark List methods

-(IBAction)saveList:(id)sender {
    NSString *listTitle = [[self listViewNameField] stringValue];
    [NSApp endSheet:[self window] returnCode:1];
    [[self listViewNameField] setStringValue:@""];

    NSArray *duplicates = [[self managedObjectContext] fetchObjectsForEntityName:RNEntityNameList withPredicate:[NSPredicate predicateWithFormat:@"title LIKE %@", listTitle]];
    if ([listTitle length] == 0 || [duplicates count] > 0)
        return;

    RNList *newList = [NSEntityDescription insertNewObjectForEntityForName:RNEntityNameList inManagedObjectContext:[self managedObjectContext]];
    [newList setTitle:listTitle];
    if ([[newList title] rangeOfString:@"grocer" options:NSCaseInsensitiveSearch].location != NSNotFound)
        [newList setIcon:[NSImage imageNamed:@"sourceList_grocery.png"]];
    else 
        [newList setIcon:[NSImage imageNamed:@"sourceList_list.png"]];
}

@end
